home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-06-20 | 13.9 KB | 489 lines | [TEXT/MPS ] |
- ; Bitmap rotation routines
-
- ; Copyright © 1989 Bob Spence
- ; All rights reserved.
-
- INCLUDE 'QuickEqu.a'
- INCLUDE 'Traps.a'
-
- ;
- ; Rotation States
- ;
- ; no rotation rotate 180
- ; (0) 1 2 (X) 4 3
- ; 3 4 2 1
- ;
- ; mirror mirror
- ; horizontal vertical
- ; (H) 2 1 (V) 3 4
- ; 4 3 1 2
- ;
- ; rotate left rotate right
- ; (L) 2 4 (R 3 1
- ; 1 3 4 2
- ;
- ; flip left flip right
- ; (FL) 1 3 (FR) 4 2
- ; 2 4 3 1
- ;
-
- ;
- ; Rotation State Table
- ;
- ; Rotate Mirror Mirror Rotate Rotate
- ; State 180 Horiz Vert Left Right FL FR
- ;
- ; 0 X H V L R FL FR
- ; H V 0 X FL FR L R
- ; V H X 0 FR FL R L
- ; X 0 V H R L FR FL
- ; L R FR FL X 0 H V
- ; R L FL FR 0 X V H
- ; FL FR R L V H 0 X
- ; FR FL L R H V X 0
- ;
-
- ; typedef enum {Rot0, RotH, RotV, RotX,
- ; RotL, RotR, RotFR, RotFL} RotationSw;
-
- Rot0 EQU 0
- RotH EQU 1
- RotV EQU 2
- RotX EQU 3
- RotL EQU 4
- RotR EQU 5
- RotFL EQU 6
- RotFR EQU 7
-
- ; PROCEDURE CalcRotate(OldState, NewRotate: RotationSw): RotationSw;
- ; parameter offsets (in Pascal order)
- NEW_ROTATE EQU 4+4
- OLD_STATE EQU NEW_ROTATE+4
-
- EXPORT CALC_ROTATE
- CALC_ROTATE PROC
- Link A6,#0
- Move.L OLD_STATE(A6),D0 ; Get the rotation state
- Lsl.W #3,D0
- Add.W NEW_ROTATE(A6),D0 ; Apply the new rotation
- And.W #$3F,D0
- Move.L RotState,A0 ; Point to the transformation table
- Move.B (A0,D0.W),-2(A6) ; Return the resultant rotation state
- Unlk A6
- Move.L (sp)+,A0 ; Get return address and
- Add.L #8,sp ; pop parameters off stack
- Jmp (A0) ; for a Pascal style return
-
- RotState ; Indexed by state and rotation, giving new rotation state
- DC.B Rot0, RotX, RotH, RotV, RotL, RotR, RotFL,RotFR
- DC.B RotH, RotV, Rot0, RotX, RotFL,RotFR,RotL, RotR
- DC.B RotV, RotH, RotX, Rot0, RotFR,RotFL,RotR, RotL
- DC.B RotX, Rot0, RotV, RotH, RotR, RotL, RotFR,RotFL
- DC.B RotL, RotR, RotFR,RotFL,RotX, Rot0, RotH, RotV
- DC.B RotR, RotL, RotFL,RotFR,Rot0, RotX, RotV, RotH
- DC.B RotFL,RotFR,RotR, RotL, RotV, RotH, Rot0, RotX
- DC.B RotFR,RotFL,RotL, RotR, RotH, RotV, RotX, Rot0
-
- ENDPROC
-
- ; The user may also select rotation of the image 90° left, right, or
- ; 180° as well as mirroring of the image horizontally and vertically.
-
-
-
- ; Register usage
- ; A0 = Input bitmap or current data pointer
- ; A1 = Output bitmap or current data pointer
- ; D0 & D1 = temp variables
- ; D2..D7 = part of 16 word rotation matrix
-
- ; Named register storage
-
- InBase EQU A2 ; Input BitMap row base address (when rotated)
- OutBase EQU A2 ; Output BitMap row base address (when mirrored)
- InBytes EQU A3 ; Input BitMap rowBytes
- xD0 EQU A4 ; Temp storage for D0 in D0..D7 data block
- xD1 EQU A5 ; Temp storage for D1 in D0..D7 data block
-
- ; Local variable stack offsets
-
- RowPtr EQU -4 ; Temp storage for output word pointer
- LowBound EQU RowPtr-4 ; Lowest output word address
- HiBound EQU LowBound-4 ; Highest output word address
- OutBytes EQU HiBound-2 ; Output BitMap rowBytes
- InWords EQU OutBytes-2 ; Words in an input row (-1 for Dbra))
- InRows EQU InWords-2 ; Rows in the input BitMap
- OutRows EQU InRows-2 ; Rows in the output BitMap
- WordCnt EQU OutRows-2 ; Temp storage for Word loop counter
- LOCALSZ EQU WordCnt-2 ; Total space needed for local variables
-
- ; The following Macros are used to:
- ; Initialize the rotation loops
- ; Load registers with input to transform
- ; Transform the data
- ; Loop thru the data as needed, and return
-
- ;
- ; Macros used to rotate a BitMap [left, right, flip left, flip right]
- ;
- ; Used by LOAD_REGS to fill a D register with the next 2 column words
- MACRO
- LOAD_REG &Dreg
- Move.W (A0),&Dreg ; Get a word
- Add.L InBytes,A0 ; Drop to next row
- Swap &Dreg ; Put it into hi word
- Move.W (A0),&Dreg ; Get a word
- Add.L InBytes,A0 ; Drop to next row
- Swap &Dreg ; Restore 1st word low, 2nd word hi
- ENDM
-
- ; Establish the tops of the 16 word block rotate loops and
- ; load a 16 word block of data to rotate in the D registers
- MACRO
- LOAD_REGS &Loop
- Move.L A1,RowPtr(A6) ; Save output's word address
- &Loop.Col: ; Top of the column loop
- Move.W InWords(A6),D0 ; Word count to process, this row
- &Loop.Row: ; Top of the row loop
- Move.W D0,WordCnt(A6) ; Save loop counter, we need D0
- Move.L A0,InBase ; Save the current input address
- ; generate LOAD_REG D0..D7
- LCLA &n
- &n SETA 0
- WHILE &n <= 7 DO
- LOAD_REG D&n
- &n SETA &n + 1
- ENDW
- Move.L D0,xD0 ; Save working D0 and D1 regs
- Move.L D1,xD1
- Add.L #2,InBase ; Point to next input word block
- Move.L InBase,A0 ; Restore the start of input
- Move.W #15,D0 ; Do 16 Dbra loops
- &Loop.Word: ; Top of the 16 bit loop
- Swap D0 ; Save bit loop count, we need a word D0
- ENDM
-
- ; Rotate a bit from the left or right (&fr) of each word in Dx
- ; into the left or right (&to) of the D0 result word
- MACRO
- RotREG &fr,&to,&Dreg
- Rox&fr..W #1,&Dreg ; Get an input bit
- Rox&to..W #1,D0 ; Set the output bit
- Swap &Dreg ; Get the 2nd, hi word
- Rox&fr..W #1,&Dreg ; Get the next input bit
- Rox&to..W #1,D0 ; Set the output bit
- Swap &Dreg ; Restore hi and lo words
- ENDM
-
- ; Get 16 bits from the 16 Dx words, rotated into D0
- MACRO
- ROT_REGS &fr,&to
- ; generate RotREG D0..D7
- LCLA &n
- &n SETA 0
- WHILE &n <= 7 DO
- IF &n <= 1 THEN
- Move.L xD&n,D1 ; xD0 and xD1 share D1
- RotREG &fr,&to,D1
- Move.L D1,xD&n
- ELSE
- RotREG &fr,&to,D&n
- ENDIF
- &n SETA &n+1
- ENDW
- Move.W D0,(A1) ; Store the rotated output word
- ENDM
-
- ; Check the word, row and column loops, cleanup, and return
- MACRO
- END_ROTATE &Loop,&AdSb1,&AdSb2
- &AdSb1..W OutBytes(A6),A1 ; Add/Subtract to next output row
- Swap D0 ; Get the bit loop count
- IF &AdSb1 = 'Add' THEN
- CMP.L HiBound(A6),A1 ; If slop on the bottom been exceeded,
- BGT.s &Loop.End ; we will go to next column
- ELSE
- CMP.L LowBound(A6),A1 ; If slop on the bottom been rotated up,
- BLT.s &Loop.End ; we will go to next column
- ENDIF
- Dbra D0,&Loop.Word
- &Loop.End
- Move.W WordCnt(A6),D0 ; Get row width word loop count
- Dbra D0,&Loop.Row
- &AdSb2..L #2,RowPtr(A6) ; Add/Sub to next output word of row
- Move.L RowPtr(A6),A1 ; Restore to start of next output word
- Move.L InBytes,D0 ; Get the input rowBytes
- Lsl.L #4,D0 ; A0 has wrapped to 1st column, 2nd word
- Sub.L InBytes,D0 ; so offset = 15 * InBytes
- Add.L D0,A0 ; Point to next A0 in word 15 rows beyond
- Sub.W #16,InRows(A6) ; Drop down to rotate next 16 rows
- Bgt &Loop.Col ; When the rows are zero, we're done
- ENDM
- ;
- ; Macros to mirror BitMaps [horizontal, vertical, 180°, null]
- ;
- ; Establish the tops of the mirroring loops
- MACRO
- GET_REG &Loop
- &Loop.Col:
- Move.L A1,OutBase ; Save the start of output
- Move.W D1,D2 ; Set the Width loop count
- &Loop.Row:
- ENDM
-
- ; Transfer a word from input to output, unchanged
- MACRO
- GET_WORD
- Move.W (A0)+,D0 ; Just get an input word, it's Ok as is
- Move.W D0,(A1)+ ; Store the word
- ENDM
-
- ; Transfer a word from input to output, bits reversed
- MACRO
- REVERSE_REG
- Move.W (A0)+,D3 ; Reverse the 16 bits in word D3
- LCLA &n
- &n SETA 0
- WHILE &n <= 15 DO
- Roxr.W #1,D3 ; Take a bit from the right
- Roxl.W #1,D0 ; and insert it to the left
- &n SETA &n + 1
- ENDW
- Move.W D0,-(A1) ; Store the word
- ENDM
-
- ; Check the word, row and column loops, cleanup, and return
- MACRO
- END_MIRROR &Loop,&ASub
- ; Loop,Add/Sub
- Dbra D2,&Loop.Row ; Loop thru row's width
- Move.L OutBase,A1 ; Restore to start of row
- &ASub..L InBytes,A1 ; Add/Sub to next row
- Sub.W #1,InRows(A6) ; Drop to next row
- Bgt.s &Loop.Col ; When the rows are zero, we're done
- ENDM
-
- ; Shift words left by the slop bits
- MACRO
- SHIFT_WORDS
- LCLA &n
- &n SETA 0
- WHILE &n <= 7 DO
- Move.W -(A0),D0 ; Get a word in the low word
- Rol.L D4,D0 ; Shift out the slop bits, round in good ones
- Move.W D0,(A0) ; Store good word
- Rol.L D3,D0 ; Shift remaining good bits to top of long word
- &n SETA &n + 1
- ENDW
- ENDM
-
- ;
- ; The bit rotation routine
- ; PROCEDURE Rotate (sourceMap, destMap: bitMap);
- ;
- ; Initialize loops, jump to specific rotation macros, and return
- ;
- ; parameter offsets (in Pascal order)
- DEST_MAP EQU 4+4
- SOURCE_MAP EQU DEST_MAP+4
- ROTATION EQU SOURCE_MAP+4
-
- Btop EQU D1 ; Some BitMap bounds Rect defines
- Bleft EQU D2
- Bbottom EQU D3
- Bright EQU D4
-
- EXPORT ROTATE
- ROTATE PROC
- Link A6,#LOCALSZ ; Allocate temporary storage
- Movem.L D2-D7/A2-A5,-(sp) ; D0-D1/A0-A1 are scratch in Pascal and C
- Move.L SOURCE_MAP(A6),A2 ; Get the source BitMap address
- Move.L DEST_MAP(A6),A1 ; Get the destination BitMap address
- Moveq #0,D0
- Move.L D0,D1
- Move.W rowBytes(A2),D1 ; Get the input rowBytes
- Move.L D1,InBytes ; Set the row byte count
- Lsr.W #1,D1 ; Convert to words
- Sub.W #1,D1 ; minus 1 (for Dbra)
- ;; Move.W D1,InWords(A6)
- Movem.W bounds(A2),D1-D4 ; Get the source bounds Rect
- Move.W Bright,D0
- Sub.W Bleft,D0
- Asr.W #4,D0 ; its words, really
- Move.W D0,InWords(A6)
- Move.W Bbottom,D0
- Sub.W Btop,D0
- Move.W D0,InRows(A6) ; Set the input number of rows
- Cmp.B #RotL,ROTATION(A6) ; Is the destination not rotated
- Blt.s NoRotate
- Sub.W Bright,D0 ; Rotate the bounds Rect
- Add.W Bleft,D0 ; (Bbottom - Btop) - (Bright - Bleft);
- Sub.W D0,Bbottom
- Add.W D0,Bright
- NoRotate
- Movem.W D1-D4,bounds(A1) ; Set the destination bounds Rect
- Move.W Bbottom,D5
- Sub.W Btop,D5
- Move.W D5,OutRows(A6) ; Set the destination row count
-
- Move.W Bright,D6 ; Compute rowBytes
- Sub.W Bleft,D6 ; forced to word boundary
- Add.W #15,D6
- Lsr.W #4,D6 ; (Bright - Bleft + 15) / 16) * 2
- Lsl.W #1,D6
- ;; Move.W D6,rowBytes(A1) ; Set the destination rowBytes
- Move.W rowBytes(A1),D6 ; Get the destination rowBytes
- Move.W D6,OutBytes(A6)
- Mulu D6,D5 ; Compute destination map size
- Addq #2,D5 ; rowBytes * (Bbottom - Btop)
- Move.L D5,D0 ; plus a fudge word for slop bits
- Addq #2,D0 ; plus one more slop word
- ;; _NewPtr ; allocate space for bitmap
- ;; Move.L A0,baseAddr(A1) ; Set the destination upper left corner
- Move.L baseAddr(A1),A0 ; Get the destination upper left corner
- Move.L A0,LowBound(A6) ; Save lowest output address
- Add.L D5,A0 ; Point beyond lower right corner
- Move.L A0,HiBound(A6) ; Save Highest output address
- Move.L baseAddr(A2),A0 ; Get the source upper left corner
- Move.W InWords(A6),D1 ; Set D1 for GET_REG Macro
-
- Moveq #0,D0
- Move.B ROTATION(A6),D0 ; Get the rotation type
- And.W #7,D0 ; Force to legal, We provide no error check, yet
- Add.W D0,D0
- Move.W Jump_Table(PC,D0),D0
- Jmp Jump_Table(PC,D0)
-
- Jump_Table
- DC.W (Rotate_0 - Jump_Table)
- DC.W (Rotate_H - Jump_Table)
- DC.W (Rotate_V - Jump_Table)
- DC.W (Rotate_X - Jump_Table)
- DC.W (Rotate_L - Jump_Table)
- DC.W (Rotate_R - Jump_Table)
- DC.W (Rotate_FL - Jump_Table)
- DC.W (Rotate_FR - Jump_Table)
- ;
- ; The Rotation and Mirror Routines
- ;
- Rotate_0
- Move.L LowBound(A6),A1 ; Point to upper left corner
- GET_REG loop0
- GET_WORD
- END_MIRROR loop0,Add
- Bra Exit_Rotate
-
- Rotate_H
- Move.L LowBound(A6),A1 ; Point beyond upper right corner
- Add.W InBytes,A1 ; for predecrement of A1 in data stores
- GET_REG loopH
- REVERSE_REG
- END_MIRROR loopH,Add
- Bra Shift_Left ; shift image left slop bits
-
- Rotate_V
- Move.L HiBound(A6),A1 ; Point beyond lower right corner
- Sub #2,A1 ; and never slop adjust
- Sub.W InBytes,A1
- GET_REG loopV
- GET_WORD
- END_MIRROR loopV,Sub
- Bra Exit_Rotate
-
- Rotate_X
- Move.L HiBound(A6),A1 ; Point beyond lower right corner
- ; for predecrement of A1 in data stores
- Move.L DEST_MAP(A6),A4 ; Get the destination BitMap address
- Move.W bounds+right(A4),D3
- Sub.W bounds+left(A4),D3 ; Number of slop bits on the left
- And.W #$0F,D3 ; Any slop bits to shift in a word ?
- Sub #2,A1 ; We don't slop adjust later in Shift_Left
- GET_REG loopX
- REVERSE_REG
- END_MIRROR loopX,Sub
- Bra Shift_Left ; shift image left slop bits
-
- Rotate_L
- Move.L HiBound(A6),A1 ; Point beyond lower right corner
- Sub.W OutBytes(A6),A1 ; Point to lower left corner
- Sub #2,A1 ; and never slop adjust
- LOAD_REGS loopL
- ROT_REGS l,l
- END_ROTATE loopL,Sub,Add
- Bra Exit_Rotate
-
- Rotate_R
- Move.L LowBound(A6),A1
- Add.W OutBytes(A6),A1
- Sub.L #2,A1 ; Point to upper right corner
- LOAD_REGS loopR
- ROT_REGS l,r
- END_ROTATE loopR,Add,Sub
- Bra Shift_Left ; shift image left slop bits
-
- Rotate_FL
- Move.L LowBound(A6),A1 ; Point to upper left corner
- LOAD_REGS loopFL
- ROT_REGS l,l
- END_ROTATE loopFL,Add,Add
- Bra Exit_Rotate
-
- Rotate_FR
- Move.L HiBound(A6),A1 ; Point beyond lower right corner
- Sub.L #2,A1 ; Point to lower right corner
- Move.L DEST_MAP(A6),A4 ; Get the destination BitMap address
- Move.W bounds+right(A4),D3
- Sub.W bounds+left(A4),D3 ; Number of slop bits on the left
- And.W #$0F,D3 ; Any slop bits to shift in a word ?
- Sub #2,A1 ; We don't slop adjust later in Shift_Left
- LOAD_REGS loopFR
- ROT_REGS l,r
- END_ROTATE loopFR,Sub,Sub
- ;; Bra Shift_Left ; shift image left slop bits
-
- ;
- ; Routines to shift the BitMap data for any slop around
- ; the edges caused by images having heights or widths
- ; which are not on word boundaries. Some rotations cause
- ; extra columns or rows to be generated to the left or top
- ; of the BitMap, we now must push the image up to the topLeft
- ; corner of the Bitmap.
- ;
- ; Shift left the output BitMap any slop columns
- Shift_Left
- Move.L DEST_MAP(A6),A4 ; Get the destination BitMap address
- Move.W bounds+right(A4),D3
- Sub.W bounds+left(A4),D3 ; Number of slop bits on the left
- And.W #$0F,D3 ; Any slop bits to shift in a word ?
- Beq.s Exit_Rotate
- Move.L baseAddr(A4),A0 ; Get the destination upper left corner
- Move.W OutBytes(A6),D1
- Move.W OutRows(A6),D2 ; Get the output rows
- Mulu D1,D2 ; Get total byte size
- Add.L D2,A0 ; Point to lower right corner
- Lsr.W #1,D2 ; Convert to words
- Moveq #16,D4
- Sub.W D3,D4 ; Number of slop bits
- Move.L D2,D5
- Lsr.L #3,D5 ; Loop count in blocks of 8 words
- Move.W D2,D1
- Neg.W D1 ; To jump into the loop doing the
- And.W #7,D1 ; block boundary remainder first
- Beq.s Bit_Loop_End
- Asl.W #3,D1 ; Multiply by code block size
- Jmp Bit_loop(PC,D1) ; Jump into the loop, part way
- Bit_loop
- SHIFT_WORDS
- Bit_Loop_End
- Dbra D5,Bit_loop
-
- Exit_Rotate
- Movem.L (sp)+,D2-D7/A2-A5
- Unlk A6
- Move.L (sp)+,A0 ; Get return address and
- Add.L #10,sp ; pop parameters off stack
- Jmp (A0) ; for a Pascal style return
- ENDPROC
-
- END
-